package com.waijiaojun.tpo.service.account;

import com.google.common.base.Objects;
import com.waijiaojun.tpo.entity.weixin.WeixinUserInfo;
import com.waijiaojun.tpo.service.weixin.WeixinUserInfoService;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.Serializable;

public class ShiroDbRealm extends AuthorizingRealm {

    private static Logger logger = LoggerFactory.getLogger(ShiroDbRealm.class);

    public static final String TEST_TOKEN = "test_00001";

    protected WeixinUserInfoService weixinUserInfoService;
    @Autowired
    public void setWeixinUserInfoService(WeixinUserInfoService weixinUserInfoService) {
        this.weixinUserInfoService = weixinUserInfoService;
    }

    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof WeixinOAuthToken; // 表示此Realm只支持WeixinOAuthToken类型
    }

    /**
     * 认证回调函数,登录时调用.
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) {
        logger.info("doGetAuthenticationInfo");
        WeixinOAuthToken token = (WeixinOAuthToken) authcToken;

        logger.info("authcToken--->>{code：" + token.getCode() + ",state：" + token.getState() + ",host:" + token.getHost() + ",rememberMe:" + token.isRememberMe() + "}");

        if (StringUtils.isBlank(token.getCode())) {
            throw new AuthenticationException("没有微信code");// 没有code
        } else if (TEST_TOKEN.equals(token.getCode())) {
            //从浏览器登录系统进入测试模式
            String openId = token.getState();//openid
            // 根据openid读取用户账号信息
            WeixinUserInfo account = weixinUserInfoService.getByOpenid(openId);
            return new SimpleAuthenticationInfo(new ShiroUser(account.getOpenid(), account.getNickname()), token.getCredentials(), getName());
        } else {
            String openId = weixinUserInfoService.receiveWeixinUserInfo(token.getCode());//拉取用户信息，并保存
            // 根据openid读取用户账号信息
            WeixinUserInfo account = weixinUserInfoService.getByOpenid(openId);

            return new SimpleAuthenticationInfo(new ShiroUser(account.getOpenid(), account.getNickname()), token.getCredentials(), getName());
        }


    }

    /**
     * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        return new SimpleAuthorizationInfo();
    }

    /**
     * 自定义Authentication对象，使得Subject除了携带用户的登录名外还可以携带更多信息.
     */
    public static class ShiroUser implements Serializable {
        private static final long serialVersionUID = -1373760761780840081L;

        private String openid;
        private String nickname;

        /**
         * @param openid
         */
        public ShiroUser(String openid, String nickname) {
            this.openid = openid;
            this.nickname = nickname;
        }


        public String print() {
            return ToStringBuilder.reflectionToString(this);
        }

        public String getOpenid() {
            return openid;
        }

        public String getNickname() {
            return nickname;
        }

        public void setNickname(String nickname) {
            this.nickname = nickname;
        }

        /**
         * 本函数输出将作为默认的<shiro:principal/>输出.
         */
        @Override
        public String toString() {
            return openid;
        }

        /**
         * 重载hashCode,只计算openid;
         */
        @Override
        public int hashCode() {
            return Objects.hashCode(openid);
        }

        /**
         * 重载equals,只计算openid;
         */
        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            ShiroUser other = (ShiroUser) obj;
            if (openid == null) {
                if (other.openid != null) {
                    return false;
                }
            } else if (!openid.equals(other.openid)) {
                return false;
            }
            return true;
        }
    }
}
